﻿#include "qmlserialport.h"

QmlSerialPort::QmlSerialPort(QObject *parent)
    : QObject{parent}
{
    m_openState = false;
    m_portName = "";
    m_parity = "No";
    m_baudRate = 9600;
    m_dataBit = 8;
    m_stopBit = 1;

    // init QSerialPort signals and slots
    connect(&mQSerialPort, &QSerialPort::errorOccurred, this, &QmlSerialPort::qSerialPort_errorOccurredSlot);
}

QmlSerialPort *QmlSerialPort::getInstance()
{
    static QmlSerialPort *myQmlSerialPort = new QmlSerialPort();
    return myQmlSerialPort;
}

void QmlSerialPort::pushSwitchStatus2QmlSerialPortSlot(int channel, int state)
{
    if (m_openState == false) {
        log(QString("pushSwitchStatus2QmlSerialPortSlot Serial Not Open"));
        return ;
    }
    log(QString("pushSwitchStatus2QmlSerialPortSlot channel: %1, state:%2").arg(channel).arg(state));
    char mLogs[100] = {0};
    unsigned char sendData[4] = {0};
    sendData[0] = 0xA0;
    sendData[1] = channel;
    sendData[2] = state;
    sendData[3] = sendData[0] | (sendData[1] + sendData[2]);
    snprintf(mLogs, sizeof(mLogs), "Hex: %02X %02X %02X %02X", sendData[0], sendData[1], sendData[2], sendData[3]);
    log(QString(mLogs));
    int writed = mQSerialPort.write((char *)sendData, sizeof(sendData));
    if (writed <= 0) {
        log("Serial Port writed may be has error.");
    }
}

QStringList QmlSerialPort::availableList(void)
{
    QStringList serialList;
    log("\n\nAvailable Ports: ");
    foreach (const QSerialPortInfo &serialPortInfo, QSerialPortInfo::availablePorts()) {
        serialList << serialPortInfo.portName();
        QString logsMsg = tr("%1(%2)").arg(serialPortInfo.description(), serialPortInfo.portName());
        log(logsMsg);
        qDebug() << "\n"
             << "Port:" << serialPortInfo.portName() << "\n"
             << "Location:" << serialPortInfo.systemLocation() << "\n"
             << "Description:" << serialPortInfo.description() << "\n"
             << "Manufacturer:" << serialPortInfo.manufacturer() << "\n"
             << "Serial number:" << serialPortInfo.serialNumber() << "\n"
             << "Vendor Identifier:"
             << (serialPortInfo.hasVendorIdentifier()
                     ? QByteArray::number(serialPortInfo.vendorIdentifier(), 16)
                     : QByteArray()) << "\n"
             << "Product Identifier:"
             << (serialPortInfo.hasProductIdentifier()
                     ? QByteArray::number(serialPortInfo.productIdentifier(), 16)
                     : QByteArray());
    }
    log(QString("\n"));
    return serialList;
}

bool QmlSerialPort::open()
{
    qDebug() << "Qml Open Serial Port: " << portName();

    // databit
    if (m_dataBit < QSerialPort::Data5 || QSerialPort::Data8 < m_dataBit) {
        log(QString("unknow databit %1").arg(m_dataBit));
        return false;
    }

    // stopbit
    QSerialPort::StopBits stopbit = QSerialPort::OneStop;
    if (m_stopBit == 1.0) {
        stopbit = QSerialPort::OneStop;
    } else if (m_stopBit == 1.5) {
        stopbit = QSerialPort::OneAndHalfStop;
    } else if (m_stopBit == 2) {
        stopbit = QSerialPort::TwoStop;
    } else {
        log(QString("unknow stopbit %1").arg(m_stopBit));
        return false;
    }

    // odd or even bit
    QSerialPort::Parity parity = QSerialPort::NoParity;
    if (m_parity == "None") {
        parity = QSerialPort::NoParity;
    } else if (m_parity == "Odd") {
        parity = QSerialPort::OddParity;
    } else if (m_parity == "Even") {
        parity = QSerialPort::EvenParity;
    } else {
        log(QString("unknow parity %1").arg(m_parity));
        return false;
    }

    if (m_openState == false) {
        mQSerialPort.setPortName(m_portName);
        mQSerialPort.setBaudRate(m_baudRate);
        mQSerialPort.setDataBits((QSerialPort::DataBits)m_dataBit);
        mQSerialPort.setStopBits(stopbit);
        mQSerialPort.setParity(parity);
    }

    // Start Open Uart
    if (m_openState == false) {
        if (mQSerialPort.open(QIODevice::ReadWrite)) {
            emit openedSerialPort();
            m_openState = true;
            log(QString("Open Serial Port %1 Succeed.").arg(mQSerialPort.portName()));
        } else {
            log(QString("Open Serial Port Fail, Error Code: %1, Error Info: %2")
                    .arg(mQSerialPort.error())
                    .arg(mQSerialPort.errorString()));
            // log("Failed to open the serial port.\r\n"
            //      "1.The serial port may be occupied.\r\n"
            //      "2.Select a correct serial port.\r\n");
            return false;
        }
    } else {
        log("Serial Port is already opened.");
    }

    return true;
}

bool QmlSerialPort::close()
{
    log(QString("Qml Close Serial Port: %1").arg(mQSerialPort.portName()));
    if (m_openState == true) {
        mQSerialPort.close();
        m_openState = false;
        emit closedSerialPort();
    } else {
        log("Serial Port Already is closed.");
    }
    return true;
}

bool QmlSerialPort::openState() const
{
    return m_openState;
}

void QmlSerialPort::setOpenState(bool newOpenState)
{
    if (m_openState == newOpenState)
        return;
    m_openState = newOpenState;
    emit openStateChanged();
}

QString QmlSerialPort::portName() const
{
    return m_portName;
}

void QmlSerialPort::setPortName(const QString &newPortName)
{
    if (m_portName == newPortName)
        return;
    m_portName = newPortName;
    emit portNameChanged();
}

QString QmlSerialPort::parity() const
{
    return m_parity;
}

void QmlSerialPort::setParity(const QString &newParity)
{
    if (m_parity == newParity)
        return;
    m_parity = newParity;
    emit parityChanged();
}

int QmlSerialPort::baudRate() const
{
    return m_baudRate;
}

void QmlSerialPort::setBaudRate(int newBaudRate)
{
    if (m_baudRate == newBaudRate)
        return;
    m_baudRate = newBaudRate;
    emit baudRateChanged();
}

int QmlSerialPort::dataBit() const
{
    return m_dataBit;
}

void QmlSerialPort::setDataBit(int newDataBit)
{
    if (m_dataBit == newDataBit)
        return;
    m_dataBit = newDataBit;
    emit dataBitChanged();
}

float QmlSerialPort::stopBit() const
{
    return m_stopBit;
}

void QmlSerialPort::setStopBit(float newStopBit)
{
    if (qFuzzyCompare(m_stopBit, newStopBit))
        return;
    m_stopBit = newStopBit;
    emit stopBitChanged();
}

void QmlSerialPort::log(QString s)
{
    QString logs = "[QmlSerialPort]: " + s;
    emit logsPrintSignal(logs);
    qDebug() << logs;
}

void QmlSerialPort::qSerialPort_errorOccurredSlot(QSerialPort::SerialPortError error)
{
    log(QString("Serial Port Error Occurred, Reason Code : %1").arg(error));
    this->close();
    emit qmlSerialPort_errorOccurredSignal(error);
}
